package com.yc.sole.system.biz;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.google.common.collect.Lists;
import com.yc.sole.common.enums.CommonState;
import com.yc.sole.common.enums.MenuType;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.utils.TreeUtil;
import com.yc.sole.system.dto.MenuDto;
import com.yc.sole.system.exception.SysResultEnum;
import com.yc.sole.system.repository.MenuRepository;
import com.yc.sole.system.repository.RoleMenuRepository;
import com.yc.sole.system.request.MenuQueryReq;
import com.yc.sole.system.request.MenuReq;
import com.yc.sole.system.response.MenuResp;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2023-03-26
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class MenuBiz {

    private final MenuRepository menuRepository;
    private final RoleMenuRepository roleMenuRepository;

    /**
     * 新增
     *
     * @param menuReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveMenu(MenuReq menuReq) {
        MenuDto dto = new MenuDto();
        BeanUtil.copyProperties(menuReq, dto);
        if (dto.getParentId() == null) {
            dto.setParentId(0L);
        }
        Long parentId = menuRepository.saveMenu(dto);
        dto.setId(parentId);
        if (MenuType.MENU.equals(menuReq.getMenuType()) && menuReq.isAutoCreatePerm()) {
            List<MenuDto> menuDtoList = getCrudPermButtons(dto);
            menuRepository.saveMenus(menuDtoList);
        }
    }

    /**
     * 生成默认增删改查按钮
     *
     * @param parent
     * @return
     */
    private List<MenuDto> getCrudPermButtons(MenuDto parent) {
        List<MenuDto> menuDtoList = new ArrayList<>();

        MenuDto selectButton = new MenuDto();
        selectButton.setMenuName("查询");
        selectButton.setParentId(parent.getId());
        selectButton.setMenuType(MenuType.BUTTON);
        selectButton.setPath(getPermissionStr(parent.getPath(), "select"));
        selectButton.setState(CommonState.ENABLE);
        selectButton.setSort(1);
        menuDtoList.add(selectButton);

        MenuDto saveButton = new MenuDto();
        saveButton.setMenuName("新增");
        saveButton.setParentId(parent.getId());
        saveButton.setMenuType(MenuType.BUTTON);
        saveButton.setPath(getPermissionStr(parent.getPath(), "save"));
        saveButton.setState(CommonState.ENABLE);
        saveButton.setSort(2);
        menuDtoList.add(saveButton);

        MenuDto updateButton = new MenuDto();
        updateButton.setMenuName("修改");
        updateButton.setParentId(parent.getId());
        updateButton.setMenuType(MenuType.BUTTON);
        updateButton.setPath(getPermissionStr(parent.getPath(), "update"));
        updateButton.setState(CommonState.ENABLE);
        updateButton.setSort(3);
        menuDtoList.add(updateButton);

        MenuDto deleteButton = new MenuDto();
        deleteButton.setMenuName("删除");
        deleteButton.setParentId(parent.getId());
        deleteButton.setMenuType(MenuType.BUTTON);
        deleteButton.setPath(getPermissionStr(parent.getPath(), "delete"));
        deleteButton.setState(CommonState.ENABLE);
        deleteButton.setSort(4);
        menuDtoList.add(deleteButton);
        return menuDtoList;
    }

    /**
     * 获取权限字符
     *
     * @param path
     * @param permission
     * @return
     */
    private String getPermissionStr(String path, String permission) {
        String[] split = path.split("/");
        List<String> stringList = new ArrayList<>();
        for (String s : split) {
            if (CharSequenceUtil.isNotBlank(s)) {
                stringList.add(s);
            }
        }
        stringList.add(permission);
        return String.join(":", stringList);
    }

    /**
     * 修改
     *
     * @param menuReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateMenuById(MenuReq menuReq) {
        MenuDto menuDto = menuRepository.selectMenuById(menuReq.getId());
        if (Objects.isNull(menuDto)) {
            throw new BaseException(SysResultEnum.MENU_IS_NULL);
        }
        MenuDto dto = new MenuDto();
        BeanUtil.copyProperties(menuReq, dto);
        menuRepository.updateMenuById(dto);
        //级联修改下级
        updateMenuStateAssociated(menuDto.getId(), menuReq.getState());
    }

    /**
     * 递归修改下级菜单分组、状态、归属子系统
     *
     * @param parentId
     * @param state
     */
    private void updateMenuStateAssociated(Long parentId, CommonState state) {
        //根据父id查询下级菜单
        List<MenuDto> children = menuRepository.selectByParentId(parentId);
        if (CollUtil.isNotEmpty(children)) {
            for (MenuDto child : children) {
                MenuDto updateMenuDto = new MenuDto();
                updateMenuDto.setId(child.getId());
                updateMenuDto.setState(state);
                menuRepository.updateMenuById(updateMenuDto);
            }
            for (MenuDto menuDto : children) {
                //存在下级菜单,递归修改下级菜单分组、状态、归属子系统
                if (Objects.nonNull(menuDto.getParentId())) {
                    updateMenuStateAssociated(menuDto.getId(), state);
                }
            }
        }
    }

    /**
     * 删除
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(Collection<Long> ids) {
        // 删除菜单
        menuRepository.deleteMenuByIds(ids);
        // 删除角色菜单关联
        roleMenuRepository.deleteByMenuIds(ids);
        for (Long id : ids) {
            //递归删除下级菜单、按钮
            deleteMenuAssociated(id);
        }
    }

    /**
     * 递归删除下级菜单、按钮
     *
     * @param parentId
     */
    private void deleteMenuAssociated(Long parentId) {
        //根据父id查询下级菜单
        List<MenuDto> children = menuRepository.selectByParentId(parentId);
        if (CollUtil.isNotEmpty(children)) {
            for (MenuDto child : children) {
                menuRepository.deleteMenuByIds(Lists.newArrayList(child.getId()));
            }
            for (MenuDto menuDto : children) {
                //存在下级菜单，递归修改下级菜单分组、状态、归属子系统
                if (Objects.nonNull(menuDto.getParentId())) {
                    deleteMenuAssociated(menuDto.getId());
                }
            }
        }
    }

    /**
     * 菜单树
     *
     * @param request
     * @return
     */
    public List<MenuResp> selectMenuTree(MenuQueryReq request) {
        List<MenuDto> menuDtos = menuRepository.selectMenuList(request);
        return TreeUtil.listToTree(BeanUtil.copyToList(menuDtos, MenuResp.class));
    }

    /**
     * 通过Id查询菜单
     *
     * @param menuId
     * @return
     */
    public MenuResp selectMenuById(Long menuId) {
        return BeanUtil.copyProperties(menuRepository.selectMenuById(menuId), MenuResp.class);
    }
}
